﻿#include <QCoreApplication>
#include <QTcpSocket>
#include <QBuffer>
#include <QDateTime>
#include <QTimer>
#include <QJsonObject>
#include <QJsonArray>
#include <QHostAddress>
#include <QJsonDocument>
#include <QProcess>
#include "TcpClientRobot.h"
#include "BaseLib/EngineProject.h"
#include "BaseLib/ProtocolStream.h"
#include "ImgSrc/ImageSrcDev.h"

#ifdef Q_OS_LINUX
#include <unistd.h>
#elif defined (Q_OS_WIN)
#include <io.h>
#include <process.h>
#endif

TcpClientRobot *TcpClientRobot::s_pInstance = nullptr;

TcpClientRobot::TcpClientRobot(int id, EngineProject *project) :
    EngineObject(id, project),
    m_serverIp("rebot_server_ip", "127.0.0.1", this),
    m_serverPort("rebot_server_port", 8050, this),
    m_reconnInterval("rebot_reconnect_interval", 5000, this),
    m_start_code("rebot_start_code", "@", this),
    m_split_code("rebot_split_code", ",", this),
    m_end_code("rebot_end_code", "$", this),
    m_graspDevTypeList("grasp_device_type", QJsonArray(), this),
    m_socket(new QTcpSocket(this)),
    m_timer(new QTimer(this))
{
    Q_ASSERT(!s_pInstance);
    s_pInstance = this;

    m_serverIp.defineSetter([this](const QJsonValue &, const QJsonValue &, bool) {
        resetTcpConfig();
        return true;
    });

    m_serverPort.defineSetter([this](const QJsonValue &, const QJsonValue &, bool) {
        resetTcpConfig();
        return true;
    });

    //重写定时间间隔的set方法
    m_reconnInterval.defineSetter([this](const QJsonValue &newValue, const QJsonValue &oldValue, bool) {
        QMetaObject::invokeMethod(this, "setIntervalAsync",
                                  Q_ARG(int, newValue.toInt()),
                                  Q_ARG(int, oldValue.toInt()));
        return true;
    });

    connect(m_timer, SIGNAL(timeout()), SLOT(onTimeout()));
    connect(m_socket, SIGNAL(connected()), SLOT(onConnected()));
    connect(m_socket, SIGNAL(disconnected()), SLOT(onDisconnected()));
    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onDisconnected()));
    connect(m_socket, SIGNAL(readyRead()), SLOT(onReadyRead()));
}

bool TcpClientRobot::init()
{
    m_timer->setInterval(m_reconnInterval.value().toInt()); // 断线5秒后重连
    m_timer->setSingleShot(true);

    moveToThread(&m_thread);
    m_thread.setObjectName(metaObject()->className());
    m_thread.start();

    return true;
}

void TcpClientRobot::cleanup()
{
    m_timer->deleteLater();
    m_socket->deleteLater();

    m_thread.quit();
    m_thread.wait();
}

void TcpClientRobot::onStarted()
{
    QMetaObject::invokeMethod(this, "onTimeout");
}

QStringList TcpClientRobot::graspDevTypeList() const
{
    QStringList tmpList;
    foreach (auto tmp, m_graspDevTypeList.value().toArray()) {
        tmpList.append(tmp.toString());
    }
    return tmpList;
}

void TcpClientRobot::onTimeout()
{
    if (!project()->getRobotOnline()) {
        if (m_socket->isOpen()) {
            m_socket->abort();
        }
        m_socket->connectToHost(m_serverIp.value().toString(), m_serverPort.value().toInt());
    }
}

void TcpClientRobot::onConnected()
{
    qInfo().noquote() << tr("Robot TcpClient: server %1:%2 connected, localport=%3")
                         .arg(m_socket->peerName())
                         .arg(m_socket->peerPort())
                         .arg(m_socket->localPort());
    project()->setRobotOnline(true);
    m_timer->start();   // 注册失败重注册
}

void TcpClientRobot::onDisconnected()
{
    qInfo().noquote() << tr("Robot TcpClient: tcp disconnected");
    m_socket->disconnectFromHost();
    project()->setRobotOnline(false);
    m_timer->start();   // 启动断线重连
}

// 系统接收控制消息，发送信号
void TcpClientRobot::onReadyRead()
{
    QByteArray body = m_socket->readAll();
    if(!body.isEmpty()) {
        return;
    }

    qDebug().noquote() << tr("Robot TcpClient: json data :") << body.data();

    QJsonObject ackBody;
    QJsonParseError jsonError;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(body, &jsonError));
    QJsonObject jsonObj = jsonDoc.object();

#ifdef USING_BUS_WAL_HEAD_ROBOT
    // 判断json是否解析成功
    // 注意：个别指令的包体可能为空
    if ((jsonError.error != QJsonParseError::NoError) && head.msgLen) {

        qInfo() <<"Robot TcpClient: json error :"<< jsonError.errorString();
        ackBody.insert("code", CTRL_ERROR);
        ackBody.insert("message", "Bad Request");

        respondToTcpRobot(head, ackBody);
#else
    // 注意：包不允许为空
    if ((jsonError.error != QJsonParseError::NoError) && !body.isEmpty()) {
#endif
        return;
    }

#ifdef USING_BUS_WAL_HEAD_ROBOT
    if ((jsonError.error != QJsonParseError::NoError) && head.msgLen) {
#else
    if ((jsonError.error != QJsonParseError::NoError) && body.isEmpty()) {
#endif
        qInfo() <<"Robot TcpClient: json error :"<< jsonError.errorString();
        ackBody.insert("code", CTRL_ERROR);
        ackBody.insert("message", "Bad Request");

#ifdef USING_BUS_WAL_HEAD_ROBOT
        respondToTcpRobot(head, ackBody);
#else
        respondToTcpRobot(body);
#endif
        return;
    }

    switch (11) {
        default:
            qInfo() <<"Robot TcpClient: json error :"<< jsonError.errorString();
            ackBody.insert("code", CTRL_ERROR);
            ackBody.insert("message", "Bad Request");

//            respondToTcpRobot(head, ackBody);
            break;
    }
}

void TcpClientRobot::resetTcpConfig()
{
    if (m_socket->isValid()) {
        m_socket->disconnectFromHost();
        project()->setRobotOnline(false);
        QMetaObject::invokeMethod(this, "onTimeout");
    }
}

void TcpClientRobot::respondToTcpRobot(const QByteArray &rebotMsg)
{
    sendToTcpRobot(rebotMsg);
}

QString TcpClientRobot::sendRunCoord(const QList<double> &farray, int graspDevId)
{
    QString runCoord;
    // 坐标xyz + 法向量abc
    if (farray.size() < 6) {
        return QString::Null();
    }

    QStringList list;
    // 起始符
    list.append(m_start_code.value().toString());
    for (int i = 0; i < farray.size(); ++i) {
        list.append(QString::number(farray.at(i)));
    }
    // 抓具类型
    list.append(QString::number(graspDevId));
    // 终止符
    list.append(m_end_code.value().toString());
    runCoord = list.join(m_split_code.value().toString());

    QByteArray sendDate;
    sendDate.append(runCoord);
    sendToTcpRobot(sendDate.data());
    return runCoord;
}

void TcpClientRobot::sendToTcpRobot(const QByteArray &rebotMsg)
{
    QMetaObject::invokeMethod(this, "sendToTcpRobotAsync", Q_ARG(QByteArray, rebotMsg));
}

void TcpClientRobot::sendToTcpRobotAsync(const QByteArray &rebotMsg)
{
    qDebug().noquote() <<"report message: " << rebotMsg.data();
    if (m_socket->isWritable()) {
        m_socket->write(rebotMsg);
    }
}

void TcpClientRobot::setIntervalAsync(const int newValue, const int oldValue)
{
    if (newValue != oldValue) {
        m_timer->setInterval(newValue);
    }
}
